import * as THREE from 'three'
import { emit } from '../../utils/EventBus.js'
export class Player {
    constructor(camera) {
        this.camera = camera
        this.eyeHeight = 1.7
        // todo  这应该使用 rapier的值
        this.gravity = 9.81
        this.velocity = new THREE.Vector3()
        this.direction = new THREE.Vector3()
        this.keyStates = {}
        this.keydown = (event) => {
            this.keyStates[event.code] = true
        }
        this.keyup = (event) => {
            this.keyStates[event.code] = false
        }
        this.mousemove = (event) => {
            if (document.pointerLockElement === document.body) {
                this.camera.rotation.y -= event.movementX / 1000
                this.camera.rotation.x -= event.movementY / 1000
            }
        }
        this.lockChangeAlert = () => {
            if (document.pointerLockElement) {
                console.log('指针锁定')
                this.lock()
                emit('collision', true)
            } else {
                console.log('指针解锁')
                this.unlock()
                emit('collision', false)
                /*
                document.body.ownerDocument.exitPointerLock()
                如果你想禁用 ESC 键退出锁定，这是不可能的 - 浏览器强制保留这个安全机制
                但你可以监听事件并尝试重新锁定：
                document.addEventListener('pointerlockchange', () => {
                    if (!document.pointerLockElement) {
                        // 用户按了ESC退出锁定
                        // 可以在这里尝试重新锁定或执行其他操作
                    }
                })
                    */
            }
        }

        this.init()
        this.t23()
    }

    t23() {
        const button = document.createElement('button')
        button.textContent = '第一人称-FP2'
        button.style.cssText = `
        position: fixed;
        top: 1%;
        right: 1%;
        text-align: center;
        z-index: 9999;
        `
        document.body.appendChild(button)

        button.addEventListener('mousedown', () => {
            document.body.requestPointerLock()
        })
    }
    init() {
        document.addEventListener(
            'pointerlockchange',
            this.lockChangeAlert,
            false
        )
    }
    destroy() {
        document.removeEventListener(
            'pointerlockchange',
            this.lockChangeAlert,
            false
        )
    }

    on() {
        document.addEventListener('keydown', this.keydown)
        document.addEventListener('keyup', this.keyup)
        document.body.addEventListener('mousemove', this.mousemove)
    }
    off() {
        document.removeEventListener('keydown', this.keydown)
        document.removeEventListener('keyup', this.keyup)
        document.body.removeEventListener('mousemove', this.mousemove)
    }
    lock() {
        this.on()
        this.save()
    }

    unlock() {
        this.off()
        this.restore()
    }

    save() {
        const { camera, velocity, eyeHeight } = this

        camera.mapPosition = camera.position.clone()
        camera.mapRotation = camera.rotation.clone()

        camera.rotation.order = 'YXZ'
        if (camera.fpPosition) {
            camera.position.copy(camera.fpPosition.clone())
            camera.rotation.copy(camera.fpRotation.clone())
        } else {
            camera.position.set(1, eyeHeight, 1)
            camera.lookAt(0, eyeHeight, 0)
        }
    }
    restore() {
        const { camera } = this

        camera.fpPosition = camera.position.clone()
        camera.fpRotation = camera.rotation.clone()

        camera.rotation.order = 'XYZ'
        camera.rotation.copy(camera.mapRotation.clone())
        camera.position.copy(camera.mapPosition.clone())
    }

    getForwardVector() {
        const { camera, direction } = this
        camera.getWorldDirection(direction)
        direction.y = 0
        direction.normalize()
        return direction
    }

    getSideVector() {
        const { camera, direction } = this
        camera.getWorldDirection(direction)
        direction.y = 0
        direction.normalize()
        direction.cross(camera.up)
        return direction
    }

    controls(deltaTime, isGrounded) {
        // gives a bit of air control
        const speedDelta = deltaTime * (isGrounded ? 25 : 8)

        const { keyStates, velocity } = this
        if (keyStates['KeyW']) {
            velocity.add(this.getForwardVector().multiplyScalar(speedDelta))
        }

        if (keyStates['KeyS']) {
            velocity.add(this.getForwardVector().multiplyScalar(-speedDelta))
        }

        if (keyStates['KeyA']) {
            velocity.add(this.getSideVector().multiplyScalar(-speedDelta))
        }

        if (keyStates['KeyD']) {
            velocity.add(this.getSideVector().multiplyScalar(speedDelta))
        }

        if (isGrounded) {
            if (keyStates['Space']) {
                velocity.y = 3
            }
        }
    }

    getTranslation(deltaTime, isGrounded) {
        this.controls(deltaTime, isGrounded)

        const { velocity, gravity } = this

        let damping = Math.exp(-4 * deltaTime) - 1

        if (!isGrounded) {
            velocity.y -= gravity * deltaTime

            // small air resistance
            damping *= 0.1
        }

        velocity.addScaledVector(velocity, damping)

        return velocity.clone().multiplyScalar(deltaTime)
    }
}
